/* Main header for user applications */

#ifndef MC_MEMCHART_HPP
#define MC_MEMCHART_HPP

#include <cstddef>
#include <new>
#include <typeinfo>

#include <memchart/add_base.hpp>
#include <memchart/add_member.hpp>
#include <memchart/rt_class_info.hpp>
#include <memchart/rt_data_source.hpp>
#include <memchart/types.hpp>

/* The macros intended for use in user classes */

/* Override operator new to track objects */
#define MC_OPERATOR_NEW(class_name) \
	void *operator new (std::size_t size) throw (std::bad_alloc) \
	{ \
		void *res = ::operator new(size); \
		\
		memchart::rt_data_source::add_obj(res, _memchart_class_info()); \
		\
		return res; \
	} \
	\
	void *operator new (std::size_t size, \
		const std::nothrow_t & nothrow) throw () \
	{ \
		void *res = ::operator new(size, nothrow); \
		\
		if (res) \
			memchart::rt_data_source::add_obj(res, _memchart_class_info()); \
		\
		return res; \
	}

/* Override operator delete */
#define MC_OPERATOR_DELETE(class_name) \
	void operator delete (void *ptr) throw () \
	{ \
		if (ptr) \
			memchart::rt_data_source::del_obj(ptr); \
		\
		::operator delete(ptr); \
	} \
	\
	void operator delete (void *ptr, const std::nothrow_t & nothrow) throw () \
	{ \
		if (ptr) \
			memchart::rt_data_source::del_obj(ptr); \
		\
		::operator delete(ptr, nothrow); \
	}

#ifndef NDEBUG

	/* Start class information definition */
	#define MC_BEGIN(class_name) \
		MC_OPERATOR_NEW(class_name) \
		MC_OPERATOR_DELETE(class_name) \
		\
		static const memchart::rt_class_info & _memchart_class_info () \
		{ \
			typedef class_name type; \
			\
			static memchart::rt_member_vector members; \
			\
			if (members.empty()) \
			{

	/* Add base class members */
	#define MC_BASE(base) \
				memchart::add_base<type, base>(members);

	/* Add class member m */
	#define MC_MEMBER(m) \
				MC_ADD_MEMBER(members, #m, &type::m);

	/* End class information definition */
	#define MC_END \
			} \
			\
			static const memchart::rt_class_info info(typeid(type).name(), \
				members); \
			\
			return info; \
		}

#else /* NDEBUG defined */

	#define MC_BEGIN(class_name)
	#define MC_BASE(base)
	#define MC_MEMBER(m)
	#define MC_END

#endif /* NDEBUG */

/* Bring update() to the top namespace */
namespace memchart
{
	static inline void update (const string & s = "")
	{
		#ifndef NDEBUG
			rt_data_source::update(s);
		#else
			static_cast<void>(s);
		#endif
	}
}

#endif /* MC_MEMCHART_HPP */
